
#include <cassert>
#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>
#include <string>
#include <vector>
using namespace std;
using json = nlohmann::json;

// example enum type declaration
enum class TaskState { TS_STOPPED = 100, TS_RUNNING = 11, TS_COMPLETED = 12 };
enum class TaskState2 { TS_STOPPED = 100, TS_RUNNING = 11, TS_COMPLETED = 12 };

// map TaskState values to JSON as strings
NLOHMANN_JSON_SERIALIZE_ENUM(TaskState,
                             {
                                 {TaskState::TS_STOPPED, "stopped"},
                                 {TaskState::TS_RUNNING, "running"},
                                 {TaskState::TS_COMPLETED, "completed"},
                             })
// 实际使用时需要设置set检查string是否正常,因为即使输入非法,但还是会得到一个错误的解
NLOHMANN_JSON_SERIALIZE_ENUM(TaskState2,
                             {
                                 {TaskState2::TS_STOPPED, "stopped"},
                                 {TaskState2::TS_RUNNING, "running"},
                                 {TaskState2::TS_COMPLETED, "completed"},
                             })
struct person {
  std::string name;
  std::string address;
  int age;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)

int main() {
  // enum to JSON as string
  json j = TaskState::TS_STOPPED;
  assert(j == "stopped");
  cout << j << endl;
  // json string to enum
  json j3 = "running";
  assert(j3.get<TaskState>() == TaskState::TS_RUNNING);
  cout << j3 << endl;
  // undefined json value to enum (where the first map entry above is the
  // default)
  json jPi = 3.14;
  //   assert(jPi.get<TaskState>() == TS_INVALID);
  switch (jPi.get<TaskState>()) {
  case TaskState::TS_STOPPED:
    cout << "TaskState::TS_STOPPED" << endl;
    break;

  default:
    break;
  }
  cout << jPi << endl;

  json jt = {{"stopped22", "stopped"}, {"abc", 0}};
  cout << jt << endl;
  auto str = jt["stopped22"];
  cout << str << endl;
  cout << (jt["stopped222"].get<TaskState>() == TaskState::TS_STOPPED) << endl;

  // str还是json对象
  switch (str.get<TaskState>()) {
  case TaskState::TS_STOPPED:
    cout << "TaskState::TS_STOPPED" << endl;
    break;

  default:
    break;
  }
  TaskState tk = TaskState::TS_RUNNING;
  json jtk = tk;
  cout << jtk << endl;
  // 运行通过
  switch (str.get<TaskState2>()) {
  case TaskState2::TS_STOPPED:
    cout << "TaskState2::TS_STOPPED" << endl;
    break;

  default:
    break;
  }

  json o;
  o["foo"] = 23;
  o["bar"] = false;
  o["baz"] = 3.141;
//    o["fdfjjf"].get<int>();
  // also use emplace
  o.emplace("weather", "sunny");

  // special iterator member functions for objects
  for (json::iterator it = o.begin(); it != o.end(); ++it) {
    std::cout << it.key() << " : " << it.value() << "\n";
  }

  // the same code as range for
  for (auto &el : o.items()) {
    std::cout << el.key() << " : " << el.value() << "\n";
  }

  // even easier with structured bindings (C++17)
  //   for (auto &[key, value] : o.items()) {
  //     std::cout << key << " : " << value << "\n";
  //   }

  // find an entry
  if (o.contains("foo")) {
    cout << "there is an entry with key \"foo\"" << endl;
  }
  if (!o.contains("fo")) {
    cout << "there is no an entry with key \"fo\"" << endl;
  }

  person per{"ding", "xian", 24};
  json pj;
  pj["name"] = per.name;
  pj["address"] = per.address;
  pj["age2"] = per.age;

  person p2 = pj.get<person>();
  cout << p2.age << endl;
  return 0;
}

// create an object
// json o;
// o["foo"] = 23;
// o["bar"] = false;
// o["baz"] = 3.141;

// // also use emplace
// o.emplace("weather", "sunny");

// // special iterator member functions for objects
// for (json::iterator it = o.begin(); it != o.end(); ++it) {
//   std::cout << it.key() << " : " << it.value() << "\n";
// }

// // the same code as range for
// for (auto& el : o.items()) {
//   std::cout << el.key() << " : " << el.value() << "\n";
// }

// // even easier with structured bindings (C++17)
// for (auto& [key, value] : o.items()) {
//   std::cout << key << " : " << value << "\n";
// }

// // find an entry
// if (o.contains("foo")) {
//   // there is an entry with key "foo"
// }
